/*
 * Copyright 2009-2010 Belmont Software Services
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.belmont.backup.client;

import java.util.*;
import com.google.gwt.core.client.*;
import com.google.gwt.user.client.*;
import com.google.gwt.user.client.ui.*;
import com.google.gwt.user.client.rpc.*;
import com.google.gwt.event.dom.client.*;
import com.google.gwt.event.logical.shared.*;

public class ClientOptionsPanel extends UIPanel implements ValueChangeHandler<Boolean> {
    static final int INCLUDE_FILTER_INDEX = 0;
    static final int EXCLUDE_FILTER_INDEX = 1;
    static final int DISK_QUOTA_INDEX = 2; // disabled
    static final int MAX_VERSIONS_INDEX = 2;
    static final int BACKUP_DIRS_INDEX = 3;
    static final int SCHEDULE_INDEX = 4;
    static final int RESTORE_DIR_INDEX = 5;
    static final int ALLOWED_HOSTS_INDEX = 6;

    TextBox includeFilters = new TextBox();
    ListBox includeFiltersList = new ListBox();
    TextBox newIncludeFilter = new TextBox();
    Button addIncludeFilter = new Button("Add");
    Button delIncludeFilter = new Button("Delete");
    TextBox excludeFilters = new TextBox();
    TextBox diskQuota = new TextBox();
    TextBox backupVersions = new TextBox();
    TextBox backupDirectories = new TextBox();
    CheckBox allowBackupDirectoriesChange = new CheckBox();
    TextBox restoreDirectory = new TextBox();
    DeckPanel clientDeck = new DeckPanel();
    ListBox excludeFiltersList = new ListBox();
    TextBox newExcludeFilter = new TextBox();
    Button addExcludeFilter = new Button("Add");
    Button delExcludeFilter = new Button("Delete");
    CheckBox maxVersionsOption = new CheckBox();
    TextBox versionLimit = new TextBox();
    ListBox backupDirList = new ListBox();
    TextBox backupDir = new TextBox();
    Button addBackupDir = new Button("add");
    Button delBackupDir = new Button("delete");
    CheckBox diskQuotaOption = new CheckBox();
    CheckBox noSchedule = new CheckBox("None");
    CheckBox dailySchedule = new CheckBox("Daily");
    CheckBox weeklySchedule = new CheckBox("Weekly");
    ListBox hour;
    ListBox minutes;
    CheckBox Mon = new CheckBox("M");
    CheckBox Tue = new CheckBox("T");
    CheckBox Wed = new CheckBox("W");
    CheckBox Thu = new CheckBox("Th");
    CheckBox Fri = new CheckBox("F");
    CheckBox Sat = new CheckBox("Sa");
    CheckBox Sun = new CheckBox("Su");
    CheckBox configCheckNow = new CheckBox("Immediate");
    CheckBox configCheckSchedule = new CheckBox("Check Interval (in minutes):");
    TextBox configSchedule = new TextBox();
    ListBox allowedHosts = new ListBox();
    TextBox allowedHost = new TextBox();
    Button addAllowedHost = new Button("Add");
    Button delAllowedHost = new Button("Delete");

    public ClientOptionsPanel(BackupUI main) {
        super(main, "Client Options");
    }

    /*
     * Set include/exclude filters.
     * Set max backup disk quota.
     * Set max number of versions kept.
     * Set default backup directories.
     * Allow/Disallow adding/deleting to the default list.
     * Set default restore directory.
     */
    public Widget init() {
        DockPanel dp = new DockPanel();
        HTML help = new HTML("Configure options for clients of the backup service. You can define options for all clients or change options for a specific client. You can also configure which machines are allowed to backup and restore files from the Backup Service.");
        MenuBar menu = new MenuBar(true);

        clientDeck.add(createIncludeFilterPanel());
        menu.addItem("Set Include Filters", true, new Command() {
                public void execute() {
                    clientDeck.showWidget(INCLUDE_FILTER_INDEX);
                }
            });

        menu.addSeparator();

        clientDeck.add(createExcludeFilterPanel());
        menu.addItem("Set Exclude Filters", true, new Command() {
                public void execute() {
                    clientDeck.showWidget(EXCLUDE_FILTER_INDEX);
                }
            });

        menu.addSeparator();

        if (false) {
            clientDeck.add(createDiskQuotaPanel());
            menu.addItem("Set Disk Quotas", true, new Command() {
                    public void execute() {
                        clientDeck.showWidget(DISK_QUOTA_INDEX);
                    }
                });

            menu.addSeparator();
        }

        clientDeck.add(createMaxVersionsPanel());
        menu.addItem("Set Max Versions", true, new Command() {
                public void execute() {
                    clientDeck.showWidget(MAX_VERSIONS_INDEX);
                }
            });

        menu.addSeparator();

        clientDeck.add(createBackupDirectoriesPanel());
        menu.addItem("Set Backup Directories", true, new Command() {
                public void execute() {
                    clientDeck.showWidget(BACKUP_DIRS_INDEX);
                }
            });

        menu.addSeparator();

        clientDeck.add(createSchedulePanel());
        menu.addItem("Set Client Schedule", true, new Command() {
                public void execute() {
                    clientDeck.showWidget(SCHEDULE_INDEX);
                }
            });

        menu.addSeparator();


        clientDeck.add(createRestoreDirectoryPanel());
        menu.addItem("Set Restore Directory", true, new Command() {
                public void execute() {
                    clientDeck.showWidget(RESTORE_DIR_INDEX);
                }
            });

        /*
          menu.addSeparator();
          clientDeck.add(createAllowedHostsPanel());
          menu.addItem("Set Allowed Hosts", true, new Command() {
          public void execute() {
          clientDeck.showWidget(ALLOWED_HOSTS_INDEX);
          }
          });
        */

        createTaskLayout("Client Tasks:", help, menu, dp, clientDeck, true, true);

        return dp;
    }

    public void refresh() {
        main.service.getIncludeFilters(new AsyncCallback() {
                public void onFailure(Throwable caught) {
                    main.print("Communication with backup server failed.");
                }
                public void onSuccess(Object result) {
                    includeFiltersList.clear();
                    includeFiltersList.addItem("<Add Filter>");

                    if (result != null) {
                        String filters[] = (String[])result;
                        for (int i=0; i < filters.length; i++) {
                            includeFiltersList.addItem(filters[i]);
                        }
                    }
                }
            });

        main.service.getExcludeFilters(new AsyncCallback() {
                public void onFailure(Throwable caught) {
                    main.print("Communication with backup server failed.");
                }
                public void onSuccess(Object result) {
                    excludeFiltersList.clear();
                    excludeFiltersList.addItem("<Add Filter>");

                    if (result != null) {
                        String filters[] = (String[])result;
                        for (int i=0; i < filters.length; i++) {
                            excludeFiltersList.addItem(filters[i]);
                        }
                    }
                }
            });

        main.service.getBackupDirectories(new AsyncCallback<String[]>() {
                public void onFailure(Throwable caught) {
                    main.print("Communication with backup server failed.");
                }
                public void onSuccess(String list[]) {
                    backupDirList.clear();

                    if (list != null) {
                        for (int i=0; i < list.length; i++) {
                            backupDirList.addItem(list[i]);
                        }
                    }
                    if (backupDirList.getItemCount() > 0) {
                        backupDir.setText(backupDirList.getItemText(0));
                    }
                }
            });

        main.service.getAllowBackupDirChange(new AsyncCallback<Boolean>() {
                public void onFailure(Throwable caught) {
                    main.print("Communication with backup server failed.");
                }
                public void onSuccess(Boolean result) {
                    allowBackupDirectoriesChange.setValue(result);
                }
            });

        main.service.getRestoreDirectory(new AsyncCallback<String>() {
                public void onFailure(Throwable caught) {
                    main.print("Communication with backup server failed.");
                }
                public void onSuccess(String result) {
                    if (result != null) {
                        restoreDirectory.setText(result);
                    }
                }
            });

        main.service.getMaxVersions(new AsyncCallback<Integer>() {
                public void onFailure(Throwable caught) {
                    main.print("Communication with backup server failed.");
                }
                public void onSuccess(Integer result) {
                    if (result == null || result.intValue() == 0) {
                        maxVersionsOption.setValue(false);
                        versionLimit.setEnabled(false);
                    } else {
                        maxVersionsOption.setValue(true);
                        versionLimit.setEnabled(true);
                        versionLimit.setText(result.toString());
                    }
                }
            });

        main.service.getSchedule(new AsyncCallback<String>() {
                public void onFailure(Throwable caught) {
                    main.print("Communication with backup server failed.");
                }
                public void onSuccess(String result) {
                    setSchedule(result);
                }
            });

        main.service.getConfigSchedule(new AsyncCallback<String>() {
                public void onFailure(Throwable caught) {
                    main.print("Communication with backup server failed.");
                }
                public void onSuccess(String result) {
                    if (result == null) {
                        configCheckNow.setValue(true);
                        configCheckSchedule.setValue(false);
                        configSchedule.setEnabled(false);
                    } else {
                        configCheckNow.setValue(false);
                        configCheckSchedule.setValue(true);
                        configSchedule.setEnabled(true);
                        configSchedule.setText(result);
                    }
                }
            });
    }

    public void doApply() {
        int idx = clientDeck.getVisibleWidget();

        switch (idx) {
            case INCLUDE_FILTER_INDEX: // include filters
                setIncludeFilters();
                break;
            case EXCLUDE_FILTER_INDEX: // exclude filters
                setExcludeFilters();
                break;
            case BACKUP_DIRS_INDEX: // backup directories
                setBackupDirectories();
                break;
            case MAX_VERSIONS_INDEX:
                setMaxVersions();
                break;
            case SCHEDULE_INDEX:
                applySchedule();
                break;
            case RESTORE_DIR_INDEX: // restore directory
                setRestoreDirectory();
                break;
            default:
                break;
        }
    }

    Widget createSchedulePanel() {
        VerticalPanel vp = new VerticalPanel();
        HTML help = new HTML("This panel allows you set schedules that control how often clients will initiate backups automatically as well as check for new configuration changes to the backup server.");

        help.setStyleName("backup-Help-Task");
        vp.add(help);

        Grid g = new Grid(2,3);
        HorizontalPanel schedulePanel = new HorizontalPanel();
        VerticalPanel p = new VerticalPanel();
        p.add(noSchedule);
        p.add(dailySchedule);
        p.add(weeklySchedule);

        noSchedule.addValueChangeHandler(this);
        dailySchedule.addValueChangeHandler(this);
        weeklySchedule.addValueChangeHandler(this);

        schedulePanel.add(p);

        VerticalPanel p2 = new VerticalPanel();

        p2.add(new Label(" "));

        hour = new ListBox();
        minutes = new ListBox();

        for (int i=0; i < 24; i++) {
            String h = (i < 10) ? "0" : "";
            hour.addItem(h+i);
        }
        for (int i=0; i < 60; i++) {
            String h = (i < 10) ? "0" : "";
            minutes.addItem(h+i);
        }

        HorizontalPanel p4 = new HorizontalPanel();
        p4.setSpacing(4);
        p4.add(new Label("Time "));
        p4.add(hour);
        p4.add(new Label(" : "));
        p4.add(minutes);
        p2.add(p4);

        HorizontalPanel p3 = new HorizontalPanel();
        p3.add(Mon);
        p3.add(Tue);
        p3.add(Wed);
        p3.add(Thu);
        p3.add(Fri);
        p3.add(Sat);
        p3.add(Sun);
        Mon.addValueChangeHandler(this);
        Tue.addValueChangeHandler(this);
        Wed.addValueChangeHandler(this);
        Thu.addValueChangeHandler(this);
        Fri.addValueChangeHandler(this);
        Sat.addValueChangeHandler(this);
        Sun.addValueChangeHandler(this);
        p2.add(p3);

        schedulePanel.add(p2);

        addRowToControlPanel(g, 0, "Backup Schedule:", schedulePanel, 
                             "Allows setting of daily or weekly times at which backups will be automatically initiated by clients. This schedule only makes sense if there is a default list of directories to backup.");

        VerticalPanel vp2 = new VerticalPanel();
        vp2.add(configCheckNow);
        HorizontalPanel hp = new HorizontalPanel();
        hp.add(configCheckSchedule);
        hp.add(configSchedule);
        hp.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
        configCheckNow.addValueChangeHandler(this);
        configCheckSchedule.addValueChangeHandler(this);
        vp2.add(hp);
        addRowToControlPanel(g, 1, "Config Schedule:", vp2, 
                             "Allows you to specify how often config setting changes from the server are sent to the client. You can either specify that settings are always retrieved by the client when needed or else a schedule specified in number of minutes between checks by the client.");
	
        g.setWidth("100%");
        g.setCellPadding(4);
        vp.add(g);
        return vp;
    }

    Widget createIncludeFilterPanel() {
        VerticalPanel vp = new VerticalPanel();
        HTML help = new HTML("This option allows you to set a default list of include filters to restrict which files to include in backups.");

        help.setStyleName("backup-Help-Task");
        vp.add(help);

        Grid g = new Grid(3,3);

        includeFiltersList.addItem("<Add Filter>");
        includeFiltersList.setWidth("100%");
        includeFiltersList.addChangeHandler(new ChangeHandler() {
                public void onChange(ChangeEvent evt) {
                    int si = includeFiltersList.getSelectedIndex();

                    if (si != -1) {
                        newIncludeFilter.setText(includeFiltersList.getItemText(si));
                    }
                }
            });

        addIncludeFilter.addClickHandler(new ClickHandler() {
                public void onClick(ClickEvent evt) {
                    int si = includeFiltersList.getItemCount();
                    String txt = newIncludeFilter.getText();

                    for (int i=0; i < si; i++) {
                        if (txt.equals(includeFiltersList.getItemText(i))) {
                            return;
                        }
                    }

                    includeFiltersList.addItem(txt);
                }
            });

        delIncludeFilter.addClickHandler(new ClickHandler() {
                public void onClick(ClickEvent evt) {
                    int si = includeFiltersList.getItemCount();
                    String txt = newIncludeFilter.getText();

                    for (int i=0; i < si; i++) {
                        if (txt.equals(includeFiltersList.getItemText(i))) {
                            includeFiltersList.removeItem(i);
                            break;
                        }
                    }
                }
            });



        newIncludeFilter.setWidth("100%");
        addRowToControlPanel(g, 0, "Defined Include Filters:", includeFiltersList,
                             "Currently defined list of include filters. These filters will be used to decide which files to include in a backup. The filter is a string that should either match a file or directory exactly (including case) or else it should match the end of the file. For example \"junkDirectory\" will only match a file or directory with that name but a filter of \".jpg\" will also match all files that end with that extension");
        addRowToControlPanel(g, 1, "Add new filter:", newIncludeFilter,
                             "Define a new filter as a file extension of files you wish to include in a backup.");
        HorizontalPanel hp = new HorizontalPanel();
        hp.add(addIncludeFilter);
        hp.add(delIncludeFilter);
        hp.setSpacing(4);
        addRowToControlPanel(g, 2, "Actions:", hp, "Add/Delete the currently displayed filter.");
        g.setCellPadding(4);
        g.setWidth("100%");
        vp.add(g);
        return vp;
    }



    Widget createExcludeFilterPanel() {
        VerticalPanel vp = new VerticalPanel();
        HTML help = new HTML("This option allows you to set a default list of exclude filters to exclude files from a backup.");

        help.setStyleName("backup-Help-Task");
        vp.add(help);

        Grid g = new Grid(3,3);

        excludeFiltersList.addItem("<Add Filter>");
        excludeFiltersList.setWidth("100%");
        excludeFiltersList.addChangeHandler(new ChangeHandler() {
                public void onChange(ChangeEvent evt) {
                    int si = excludeFiltersList.getSelectedIndex();

                    if (si != -1) {
                        newExcludeFilter.setText(excludeFiltersList.getItemText(si));
                    }
                }
            });
        addExcludeFilter.addClickHandler(new ClickHandler() {
                public void onClick(ClickEvent evt) {
                    int si = excludeFiltersList.getItemCount();
                    String txt = newExcludeFilter.getText();

                    for (int i=0; i < si; i++) {
                        if (txt.equals(excludeFiltersList.getItemText(i))) {
                            return;
                        }
                    }

                    excludeFiltersList.addItem(txt);
                }
            });

        delExcludeFilter.addClickHandler(new ClickHandler() {
                public void onClick(ClickEvent evt) {
                    int si = excludeFiltersList.getItemCount();
                    String txt = newExcludeFilter.getText();

                    for (int i=0; i < si; i++) {
                        if (txt.equals(excludeFiltersList.getItemText(i))) {
                            excludeFiltersList.removeItem(i);
                            break;
                        }
                    }
                }
            });

        newExcludeFilter.setWidth("100%");
        addRowToControlPanel(g, 0, "Defined Exclude Filters:", excludeFiltersList,
                             "Currently defined list of exclude filters. These filters will be used to decide which files to exclude from a backup. The filter is a string that should either match a file or directory exactly (including case) or else it should match the end of the file. For example \"junkDirectory\" will only match a file or directory with that name but a filter of \".jpg\" will also match all files that end with that extension");
        addRowToControlPanel(g, 1, "Add new filter:", newExcludeFilter,
                             "Define a new filter as a file extension of files you wish to exclude in a backup.");
        HorizontalPanel hp = new HorizontalPanel();
        hp.add(addExcludeFilter);
        hp.add(delExcludeFilter);
        hp.setSpacing(4);
        addRowToControlPanel(g, 2, "Actions:", hp, "Add/Delete the currently displayed filter.");

        g.setWidth("100%");
        g.setCellPadding(4);
        vp.add(g);
        return vp;
    }

    Widget createDiskQuotaPanel() {
        VerticalPanel vp = new VerticalPanel();
        HTML help = new HTML("This option allows you to set a maximum disk quota per client for backups.");

        help.setStyleName("backup-Help-Task");
        vp.add(help);

        Grid g = new Grid(2,3);

        addRowToControlPanel(g, 0, "Set Disk Quota:", diskQuotaOption,
                             "Select in order to set disk quotas.");
        addRowToControlPanel(g, 1, "Quota Size:", diskQuota,
                             "Set a size using the suffix MB for megabytes and GB for gigabytes.");

        diskQuota.setWidth("100%");
        g.setWidth("100%");
        g.setCellPadding(4);
        vp.add(g);
        return vp;
    }

    Widget createMaxVersionsPanel() {
        VerticalPanel vp = new VerticalPanel();
        HTML help = new HTML("The backup service can keep an arbitrary number of versions for each backup. This option allows you to set an upper limit.");

        help.setStyleName("backup-Help-Task");
        vp.add(help);

        Grid g = new Grid(2,3);

        maxVersionsOption.addValueChangeHandler(this);
        addRowToControlPanel(g, 0, "Set Max Versions:", maxVersionsOption,
                             "Select in order to limit amount of versions for each backup.");
        addRowToControlPanel(g, 1, "Version Limit:", versionLimit,
                             "Set maximum number of versions. This represents the N latest versions to keep.");

        g.setWidth("100%");
        g.setCellPadding(4);
        vp.add(g);
        return vp;
    }

    Widget createBackupDirectoriesPanel() {
        VerticalPanel vp = new VerticalPanel();
        HTML help = new HTML("This option allows you to specify the default list of backup directories to backup on a client machine.");

        help.setStyleName("backup-Help-Task");
        vp.add(help);

        Grid g = new Grid(4,3);

	
        backupDirList.addChangeHandler(new ChangeHandler() {
                public void onChange(ChangeEvent evt) {
                    int si = backupDirList.getSelectedIndex();

                    if (si != -1) {
                        backupDir.setText(backupDirList.getItemText(si));
                    }
                }
            });

        addBackupDir.addClickHandler(new ClickHandler() {
                public void onClick(ClickEvent evt) {
                    int si = backupDirList.getItemCount();
                    String txt = backupDir.getText();

                    for (int i=0; i < si; i++) {
                        if (txt.equals(backupDirList.getItemText(i))) {
                            return;
                        }
                    }

                    backupDirList.addItem(txt);
                }
            });

        delBackupDir.addClickHandler(new ClickHandler() {
                public void onClick(ClickEvent evt) {
                    int si = backupDirList.getItemCount();
                    String txt = backupDir.getText();

                    for (int i=0; i < si; i++) {
                        if (txt.equals(backupDirList.getItemText(i))) {
                            backupDirList.removeItem(i);
                            break;
                        }
                    }
                }
            });
        backupDirList.setWidth("100%");
        addRowToControlPanel(g, 0,
                             "Default backup directories:",
                             backupDirList,
                             "Currently defined directories on the client to backup.");

        backupDir.setWidth("100%");
        addRowToControlPanel(g, 1, "Add directory:", backupDir,
                             "Add a new directory to the list.");
        HorizontalPanel hp = new HorizontalPanel();
        hp.add(addBackupDir);
        hp.add(delBackupDir);
        hp.setSpacing(4);
        addRowToControlPanel(g, 2, "Actions:", hp, "Add/Delete the currently displayed backup directory.");
        addRowToControlPanel(g, 3,
                             "Allow adding/deleting to backup directories:",
                             allowBackupDirectoriesChange,
                             "Whether to allow clients to add or delete to the list of directories to backup.");

        g.setWidth("100%");
        g.setCellPadding(4);
        vp.add(g);
        return vp;
    }

    public void onValueChange(ValueChangeEvent<Boolean> e) {
        Object item = e.getSource();
        boolean v = e.getValue();

        if (item == noSchedule || item == dailySchedule || item == weeklySchedule) {
            if (v) {
                if (item == noSchedule) {
                    dailySchedule.setValue(false);
                    weeklySchedule.setValue(false);
                } else if (item == dailySchedule) {
                    noSchedule.setValue(false);
                    weeklySchedule.setValue(false);
                } else if (item == weeklySchedule) {
                    dailySchedule.setValue(false);
                    noSchedule.setValue(false);
                }
                hour.setEnabled(item != noSchedule);
                minutes.setEnabled(item != noSchedule);
                Mon.setEnabled(item == weeklySchedule);
                Tue.setEnabled(item == weeklySchedule);	
                Wed.setEnabled(item == weeklySchedule);
                Thu.setEnabled(item == weeklySchedule);
                Fri.setEnabled(item == weeklySchedule);
                Sat.setEnabled(item == weeklySchedule);
                Sun.setEnabled(item == weeklySchedule);
            }
        } else if (item == Mon || item == Tue || item == Wed || item == Thu || item == Fri || item == Sat
                   || item == Sun) {
            Mon.setValue(item == Mon);
            Tue.setValue(item == Tue);
            Wed.setValue(item == Wed);
            Thu.setValue(item == Thu);
            Fri.setValue(item == Fri);
            Sat.setValue(item == Sat);
            Sun.setValue(item == Sun);
        } else if (item == maxVersionsOption) {
            versionLimit.setEnabled(maxVersionsOption.getValue());
        } else if (item == configCheckNow || item == configCheckSchedule) {
            if (item == configCheckNow) {
                configCheckSchedule.setValue(false);
                configSchedule.setEnabled(false);
            } else {
                configCheckNow.setValue(false);
                configSchedule.setEnabled(true);
            }
        }
    }

    Widget createRestoreDirectoryPanel() {
        VerticalPanel vp = new VerticalPanel();
        HTML help = new HTML("This option allows you to specify the default directory on a client machine used for any restore operations.");

        help.setStyleName("backup-Help-Task");
        vp.add(help);

        Grid g = new Grid(1,3);

        restoreDirectory.setVisibleLength(60);
        addRowToControlPanel(g, 0,
                             "Default restore directory:",
                             restoreDirectory,
                             "Currently defined default when a client restores from a backup.");


        g.setWidth("100%");
        g.setCellPadding(4);
        vp.add(g);
        return vp;
    }
    Widget createAllowedHostsPanel() {
        VerticalPanel vp = new VerticalPanel();
        HTML help = new HTML("This option allows you to specify which hosts or networks are allowed to connect to the backup service.");

        help.setStyleName("backup-Help-Task");
        vp.add(help);

        Grid g = new Grid(3,3);

        allowedHosts.setWidth("100%");
        addRowToControlPanel(g, 0,"Allowed Hosts or Networks:", allowedHosts,
                             "Currently defined list of hosts or networks that are allowed to use the service.");

        allowedHost.setWidth("100%");
        addRowToControlPanel(g, 1,"Add allowed host or network:", allowedHost,
                             "Enter a host as a fully qualified DNS name or an IP address. Or you can specify a network as an IP address followed by a netmask. For example \"192.168.2.33 255.255.0.0\".");

        HorizontalPanel hp = new HorizontalPanel();
        hp.add(addAllowedHost);
        hp.add(delAllowedHost);
        hp.setSpacing(4);
        addRowToControlPanel(g, 2, "Actions:", hp, "Add/Delete the currently displayed host or network.");

        g.setWidth("100%");
        g.setCellPadding(4);
        vp.add(g);

        return vp;	
    }

    void setMaxVersions() {
        String v = null;
        if (maxVersionsOption.getValue()) {
            v = versionLimit.getText().trim();
        }

        try {
            int l = 0;

            if (v != null) {
                l = Integer.parseInt(v);
                if (l <= 0) {
                    main.print("version limit must be greater than zero: "+l);
                    return;
                }
            }

            main.service.setMaxVersions(l, new AsyncCallback() {
                    public void onSuccess(Object result) {
                        if (maxVersionsOption.getValue()) {
                            main.print("Set max versions.");
                        } else {
                            main.print("Removed limit on max versions.");
                        }
                    }
                    public void onFailure(Throwable caught) {
                        main.print("Error setting max versions");
                    }
                });
        } catch (NumberFormatException ex) {
            main.print("version limit not a legal number: "+v);
        }
    }

    void setRestoreDirectory() {
        String r = restoreDirectory.getText();
        if (r != null) {
            r = r.trim();
            if (r.length() > 0) {
                main.service.setRestoreDirectory(r, new AsyncCallback() {
                        public void onSuccess(Object result) {
                            main.print("Restore directory set.");
                        }
                        public void onFailure(Throwable caught) {
                            main.print("Error setting restore directory.");
                        }
                    });
            }
        }
    }

    void setBackupDirectories() {
        int l = backupDirList.getItemCount();
        String list[] = null;

        if (l > 0) {
            list = new String[l];
            for (int i=0; i < l; i++) {
                list[i] = backupDirList.getItemText(i);
            }
        }

        main.service.setBackupDirectories(list, new AsyncCallback() {
                public void onSuccess(Object result) {
                    main.print("New backup directories changes applied.");
                }
                public void onFailure(Throwable caught) {
                    main.print("Error setting backup directories.");
                }
            });
        main.service.setAllowBackupDirChange(allowBackupDirectoriesChange.getValue(), new AsyncCallback() {
                public void onSuccess(Object result) {
                }
                public void onFailure(Throwable caught) {
                    main.print("Error setting backup dir change.");
                }
            });
    }

    void applySchedule() {
        main.service.setSchedule(makeScheduleString(), new AsyncCallback() {
                public void onSuccess(Object result) {
                    main.print("Applied schedule changes.");
                }
                public void onFailure(Throwable caught) {
                    main.print("Error setting backup schedule.");
                }
            });
        main.service.setConfigSchedule((configCheckNow.getValue()) ? null : configSchedule.getText(), new AsyncCallback() {
                public void onSuccess(Object result) {
                    main.print("Applied schedule changes.");
                }
                public void onFailure(Throwable caught) {
                    main.print("Error setting config schedule.");
                }
            });
    }


    String makeTimeString() {
        return hour.getItemText(hour.getSelectedIndex())+":"+minutes.getItemText(minutes.getSelectedIndex());
    }

    String makeScheduleString() {
        if (noSchedule.getValue()) {
            return "None";
        } else if (dailySchedule.getValue()) {
            return "daily:"+makeTimeString();
        } else if (weeklySchedule.getValue()) {
            String day = null;

            if (Mon.getValue()) {
                day = "Mon";
            } else if (Tue.getValue()) {
                day = "Tue";
            } else if (Wed.getValue()) {
                day = "Wed";
            } else if (Thu.getValue()) {
                day = "Thu";
            } else if (Fri.getValue()) {
                day = "Fri";
            } else if (Sat.getValue()) {
                day = "Sat";
            } else if (Sun.getValue()) {
                day = "Sun";
            }

            return "weekly:"+day+";"+makeTimeString();
        } else {
            return "None";
        }
    }

    void setIncludeFilters() {
        int l = includeFiltersList.getItemCount();
        String flist[] = null;
        if (l > 1) {
            int fl = l - 1;
            flist = new String[fl];

            for (int i=1; i < l; i++) {
                flist[i - 1] = includeFiltersList.getItemText(i);
            }
        }
        main.service.setIncludeFilters(flist, new AsyncCallback() {
                public void onSuccess(Object result) {
                    main.print("New include filters set.");
                }
                public void onFailure(Throwable caught) {
                    main.print("Error setting include filters.");
                }
            });
    }

    void setExcludeFilters() {
        int l = excludeFiltersList.getItemCount();
        String flist[] = null;
        if (l > 1) {
            int fl = l - 1;
            flist = new String[fl];

            for (int i=1; i < l; i++) {
                flist[i - 1] = excludeFiltersList.getItemText(i);
            }
        }
        main.service.setExcludeFilters(flist, new AsyncCallback() {
                public void onSuccess(Object result) {
                    main.print("New exclude filters set.");
                }
                public void onFailure(Throwable caught) {
                    main.print("Error setting exclude filters.");
                }
            });
    }

    public void setSchedule(String schedule) {
        boolean daily = false;
        boolean weekly = false;
        if (schedule != null) {
            daily = schedule.startsWith("daily");
            weekly = schedule.startsWith("weekly");
        }
        noSchedule.setValue(!daily && !weekly);
        dailySchedule.setValue(daily);
        weeklySchedule.setValue(weekly);

        hour.setEnabled(daily || weekly);
        minutes.setEnabled(daily || weekly);
        Mon.setEnabled(weekly);
        Tue.setEnabled(weekly);
        Wed.setEnabled(weekly);
        Thu.setEnabled(weekly);
        Fri.setEnabled(weekly);
        Sat.setEnabled(weekly);
        Sun.setEnabled(weekly);
        if (daily) {
            int idx = schedule.indexOf(':');
            if (idx != -1) {
                schedule = schedule.substring(idx+1);
                idx = schedule.indexOf(':');
                if (idx != -1) {
                    try {
                        String h = schedule.substring(0, idx);
                        String m = schedule.substring(idx+1);
                        hour.setSelectedIndex(Integer.parseInt(h));
                        minutes.setSelectedIndex(Integer.parseInt(m));
                    } catch (NumberFormatException ex) {
                        ex.printStackTrace();
                    }
                }
            }
        } else if (weekly) {
            int idx = schedule.indexOf(':');
            if (idx != -1) {
                schedule = schedule.substring(idx+1);
                idx = schedule.indexOf(';');
                if (idx != -1) {
                    String day = schedule.substring(0, idx);
                    Mon.setValue("Mon".equals(day));
                    Tue.setValue("Tue".equals(day));
                    Wed.setValue("Wed".equals(day));
                    Thu.setValue("Thu".equals(day));
                    Fri.setValue("Fri".equals(day));
                    Sat.setValue("Sat".equals(day));
                    Sun.setValue("Sun".equals(day));

                    schedule = schedule.substring(idx+1);
                    idx = schedule.indexOf(':');
                    if (idx != -1) {
                        try {
                            String h = schedule.substring(0, idx);
                            String m = schedule.substring(idx+1);
                            hour.setSelectedIndex(Integer.parseInt(h));
                            minutes.setSelectedIndex(Integer.parseInt(m));
                        } catch (NumberFormatException ex) {
                            ex.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}